package com.tsfyun.scm.security.config;

import com.tsfyun.common.base.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.*;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
public class StringRedisUtils {

    @Autowired
    @Qualifier("stringRedisTemplate")
    private RedisTemplate stringRedisTemplate;

    /**=
     * 写入
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key,Object value){
        try{
            ValueOperations<String, Object> valueOps = stringRedisTemplate.opsForValue();
            valueOps.set(key,value);
            return Boolean.TRUE;
        }catch (Exception e){
            log.error("Redis写入失败 :",e);
        }
        return Boolean.FALSE;
    }

    public boolean set(final String key,Object value,Long expireTime,TimeUnit timeUnit){
        try{
            ValueOperations<String, Object> valueOps = stringRedisTemplate.opsForValue();
            valueOps.set(key,value);
            stringRedisTemplate.expire(key, expireTime, timeUnit);
            return Boolean.TRUE;
        }catch (Exception e){
            log.error("Redis写入失败 :",e);
        }
        return Boolean.FALSE;
    }


    /**=
     * 写入不修改原过期值
     * @param key
     * @param value
     * @return
     */
    public boolean setKeepExpire(final String key,Object value){
        try{
            ValueOperations<String, Object> valueOps = stringRedisTemplate.opsForValue();
            //使用偏移量会有BUG，当修改的值长度比原来小的时候会出现内容异常
            //valueOps.set(key,value,0);
            valueOps.set(key,value,stringRedisTemplate.getExpire(key,TimeUnit.SECONDS),TimeUnit.SECONDS);
            return Boolean.TRUE;
        }catch (Exception e){
            log.error("Redis写入失败 :",e);
        }
        return Boolean.FALSE;
    }

    /**=
     * 读取
     * @param key
     * @return
     */
    public Object get(final String key){
        ValueOperations<String, Object> valueOps = stringRedisTemplate.opsForValue();
        return valueOps.get(key);
    }

    public String getToString(final String key){
        ValueOperations<String, Object> valueOps = stringRedisTemplate.opsForValue();
        Object val = valueOps.get(key);
        if(StringUtils.isNotEmpty(val)){
            return val.toString();
        }
        return null;
    }


    /**=
     * 判断key是否存在
     * @param key
     * @return
     */
    public boolean exists(final String key){
        return stringRedisTemplate.hasKey(key);
    }
    /**=
     * 删除
     * @param key
     * @return
     */
    public void remove(final String key) {
        if (exists(key)) {
            stringRedisTemplate.delete(key);
        }
    }

    /**
     * 计数器
     * @param key
     * @return
     */
    public Long increment(final String key,final Long skip,final long expireTime,TimeUnit timeUnit) {
        Long cnt = stringRedisTemplate.opsForValue().increment(key,skip);
        stringRedisTemplate.expire(key,expireTime,timeUnit);
        return cnt;
    }

    /**
     * 查看某key剩余时间
     * @param key
     * @return
     */
    public Long ttl(final String key) {
        Long ttl = stringRedisTemplate.opsForValue().getOperations().getExpire(key);
        //-1永久有效；-2不存在某key
        return ttl;
    }

    /**
     * 使用scan命令获取匹配key数据集
     * @param key
     * @param count
     * @return
     */
    public Set<String> scan(final String key, final long count) {
        return (Set<String>) stringRedisTemplate.execute((RedisCallback<Iterable<String>>) redisConnection -> {
            Set<String> result = new HashSet<>();
            ScanOptions scanOptions = (new ScanOptions.ScanOptionsBuilder()).match(key).count(count).build();
            Cursor c = redisConnection.scan(scanOptions);
            while (c.hasNext()) {
                String key1 = new String((byte[]) c.next());
                result.add(key1);
            }
            return result;
        });
    }

}
